﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using YArchitech.Revit;
using YJKRevitKernel.ElementSearchUtility.LinkDocumentSuite;
using YJKRevitKernel.XYZUtility;
using YJKRevitDimensionText.VerticalAutoDim.ProgressBar;

namespace YJKRevitDimensionText.VerticalAutoDim.OutWallSearch
{
	internal class OutRoomOutWallCreator : IOutWallCreator
	{
		private IDictionary<ElementId, IList<OutWallData>> MapLevelId2OutWallData { get; set; }

		public IDictionary<ElementId, IList<OutWallData>> LevelId2OutWallData
		{
			get
			{
				return this.MapLevelId2OutWallData;
			}
		}

		public Func<Element, bool> IsParapetWall
		{
			get
			{
				return new Func<Element, bool>(Utility.IsValidParapetWall);
			}
		}

		public OutRoomOutWallCreator(Autodesk.Revit.DB.Document doc, IList<ViewPlan> arrayViewPlan, IDualStatusProgressBarProcess dualStatusProgressBarProcess)
		{
			this.Doc = doc;
			this.ArrayViewPlan = arrayViewPlan;
			this.MapLevelId2OutWallData = new Dictionary<ElementId, IList<OutWallData>>();
			this.DualStatusProgressBarProcess = dualStatusProgressBarProcess;
		}

		public bool OutWallSearcher()
		{
			XYZ ViewOrientation = this.Doc.ActiveView.ViewDirection;
			int i = 0;
			this.DualStatusProgressBarProcess.UpdatePrimaryStatus(1);
			this.DualStatusProgressBarProcess.SetSubStatusMaxVal(this.ArrayViewPlan.Count);
            //Func<OutWallData, bool> <>9__1;
            //EnumerableExternsion.ForEach<ViewPlan>(this.ArrayViewPlan, delegate(ViewPlan view)
            //{
            //    List<OutWallData> list = OutRoomOutWallCreator.GetOutermostWalls(new OutRoomOutWallCreator.DetermineAdjacentElementLengthsAndWallAreasDel(OutRoomOutWallCreator.DetermineAdjacentElementLengthsAndWallAreas), this.Doc, view, false);
            //    IEnumerable<OutWallData> source = list;
            //    Func<OutWallData, bool> predicate;
            //    if ((predicate = <>9__1) == null)
            //    {
            //        predicate = (<>9__1 = ((OutWallData w) => XYZUtilityMethod.IsSameDirection(ViewOrientation, w.Orientation)));
            //    }
            //    list = source.Where(predicate).ToList<OutWallData>();
            //    this.MapLevelId2OutWallData.Add(view.Id, list);
            //    IDualStatusProgressBarProcess dualStatusProgressBarProcess = this.DualStatusProgressBarProcess;
            //    int i = i;
            //    i++;
            //    dualStatusProgressBarProcess.UpdateSubStatus(i);
            //});
			return true;
		}

		private static double GetALevelValue(Autodesk.Revit.DB.Document doc, PlanViewRange viewRange, PlanViewPlane useViewPlanKind)
		{
			double num = double.MaxValue;
			Level level = doc.GetElement(viewRange.GetLevelId(useViewPlanKind)) as Level;
			if (level != null)
			{
				num = level.Elevation;
				double offset = viewRange.GetOffset(useViewPlanKind);
				num += offset;
			}
			return num;
		}

		public static List<OutWallData> GetOutermostWalls(OutRoomOutWallCreator.DetermineAdjacentElementLengthsAndWallAreasDel del, Autodesk.Revit.DB.Document doc, Autodesk.Revit.DB.View view, bool bAutoRollBack = false)
		{
			List<OutWallData> result = new List<OutWallData>();
			TransactionGroup transactionGroup = null;
			try
			{
				if (bAutoRollBack)
				{
					transactionGroup = new TransactionGroup(doc, "GetOutermostWallsTmp");
					transactionGroup.Start();
				}
				double num = 3.2808398950131235;
				ViewPlan viewPlan = view as ViewPlan;
                double alevelValue = OutRoomOutWallCreator.GetALevelValue(doc, viewPlan.GetViewRange(), (PlanViewPlane)1);
                double alevelValue2 = OutRoomOutWallCreator.GetALevelValue(doc, viewPlan.GetViewRange(), (PlanViewPlane)2);
				BoundingBoxIntersectsFilter boundingBoxIntersectsFilter = new BoundingBoxIntersectsFilter(new Outline(new XYZ(double.MinValue, double.MinValue, alevelValue2), new XYZ(double.MaxValue, double.MaxValue, alevelValue)));
				FilteredElementCollectorLinkDocument filteredElementCollectorLinkDocument = new FilteredElementCollectorLinkDocument(doc).OfCalss(typeof(Wall));
				filteredElementCollectorLinkDocument.AddViewLimit(boundingBoxIntersectsFilter);
				List<Wall> list = (from e in filteredElementCollectorLinkDocument
				select e.UseElement).Cast<Wall>().ToList<Wall>();
				double maxX = -1.0;
				double minX = -1.0;
				double maxY = -1.0;
				double minY = -1.0;
				list.ForEach(delegate(Wall wall)
				{
					Curve curve = (wall.Location as LocationCurve).Curve;
					XYZ endPoint = curve.GetEndPoint(0);
					XYZ endPoint2 = curve.GetEndPoint(1);
					double num2 = Math.Min(endPoint.X, endPoint2.X);
					double num3 = Math.Max(endPoint.X, endPoint2.X);
					double num4 = Math.Min(endPoint.Y, endPoint2.Y);
					double num5 = Math.Max(endPoint.Y, endPoint2.Y);
					if (curve.IsCyclic)
					{
						double radius = (curve as Arc).Radius;
						num3 += radius;
						num2 -= radius;
						num5 += radius;
						num4 += radius;
					}
					if (minX == -1.0)
					{
						minX = num2;
					}
					if (maxX == -1.0)
					{
						maxX = num3;
					}
					if (maxY == -1.0)
					{
						maxY = num5;
					}
					if (minY == -1.0)
					{
						minY = num4;
					}
					if (num2 < minX)
					{
						minX = num2;
					}
					if (num3 > maxX)
					{
						maxX = num3;
					}
					if (num5 > maxY)
					{
						maxY = num5;
					}
					if (num4 < minY)
					{
						minY = num4;
					}
				});
				minX -= num;
				maxX += num;
				minY -= num;
				maxY += num;
				CurveArray curveArray = new CurveArray();
				Line line = Line.CreateBound(new XYZ(minX, maxY, 0.0), new XYZ(maxX, maxY, 0.0));
				Line line2 = Line.CreateBound(new XYZ(maxX, maxY, 0.0), new XYZ(maxX, minY, 0.0));
				Line line3 = Line.CreateBound(new XYZ(maxX, minY, 0.0), new XYZ(minX, minY, 0.0));
				Line line4 = Line.CreateBound(new XYZ(minX, minY, 0.0), new XYZ(minX, maxY, 0.0));
				curveArray.Append(line);
				curveArray.Append(line2);
				curveArray.Append(line3);
				curveArray.Append(line4);
				Room room = null;
				using (Transaction transaction = new Transaction(doc, "createNewRoomBoundaryLines"))
				{
					try
					{
						transaction.Start();
						if (view == null)
						{
							view = doc.ActiveView;
						}
						SketchPlane sketchPlane = SketchPlane.Create(doc, view.GenLevel.Id);
						doc.Create.NewRoomBoundaryLines(sketchPlane, curveArray, view);
						XYZ xyz = new XYZ(minX + 1.9685039370078738, maxY - 1.9685039370078738, 0.0);
						room = doc.Create.NewRoom(view.GenLevel, new UV(xyz.X, xyz.Y));
						if (room == null)
						{
							transaction.RollBack();
							return null;
						}
						doc.Create.NewRoomTag(new LinkElementId(room.Id), new UV(xyz.X, xyz.Y), view.Id);
						transaction.Commit();
					}
					catch
					{
						transaction.RollBack();
					}
				}
				result = del(doc, room, false);
				if (bAutoRollBack)
				{
					transactionGroup.RollBack();
				}
			}
			catch
			{
			}
			return result;
		}

		public static List<OutWallData> DetermineAdjacentElementLengthsAndWallAreas(Autodesk.Revit.DB.Document doc, Room room, bool useArcWall = false)
		{
			List<OutWallData> list = new List<OutWallData>();
			IList<IList<BoundarySegment>> boundarySegments = room.GetBoundarySegments(new SpatialElementBoundaryOptions());
			int count = boundarySegments.Count;
			foreach (IList<BoundarySegment> list2 in boundarySegments)
			{
				foreach (BoundarySegment boundarySegment in list2)
				{
					Curve curve = RevitElementExtension.GetCurve(boundarySegment);
					if (!useArcWall || curve is Line)
					{
						RevitLinkInstance revitLinkInstance = doc.GetElement(boundarySegment.ElementId) as RevitLinkInstance;
						Element element;
						if (revitLinkInstance != null)
						{
							element = revitLinkInstance.GetLinkDocument().GetElement(boundarySegment.LinkElementId);
						}
						else
						{
							element = doc.GetElement(boundarySegment.ElementId);
						}
						if (element is Wall)
						{
							Wall wall = element as Wall;
							Curve curve2 = (wall.Location as LocationCurve).Curve;
							curve2.GetEndPoint(0);
							curve2.GetEndPoint(1);
							try
							{
								XYZ xyz = curve2.Evaluate(0.5, true);
								Curve curve3 = curve.Clone();
								curve3.MakeUnbound();
								XYZ xyz2 = curve3.Project(xyz).XYZPoint - xyz;
								xyz2 = new XYZ(xyz2.X, xyz2.Y, 0.0);
								OutWallData item = new OutWallData
								{
									Curve = curve,
									Element = wall,
									Orientation = xyz2
								};
								list.Add(item);
							}
							catch
							{
							}
						}
					}
				}
			}
			return list;
		}

		private static bool IsHasWall(Autodesk.Revit.DB.Document doc, IList<BoundarySegment> boundaries)
		{
			foreach (BoundarySegment boundarySegment in boundaries)
			{
				RevitLinkInstance revitLinkInstance = doc.GetElement(boundarySegment.ElementId) as RevitLinkInstance;
				Element element;
				if (revitLinkInstance != null)
				{
					element = revitLinkInstance.GetLinkDocument().GetElement(boundarySegment.LinkElementId);
				}
				else
				{
					element = doc.GetElement(boundarySegment.ElementId);
				}
				if (element is Wall)
				{
					return true;
				}
			}
			return false;
		}

		public static List<OutWallData> DetermineAdjacentElementLengthsAndWallAreasEx(Autodesk.Revit.DB.Document doc, Room room, bool useArcWall = false)
		{
			List<OutWallData> list = new List<OutWallData>();
			IList<IList<BoundarySegment>> boundarySegments = room.GetBoundarySegments(new SpatialElementBoundaryOptions());
			int count = boundarySegments.Count;
			foreach (IList<BoundarySegment> list2 in boundarySegments)
			{
				if (list2.Count != 4 || OutRoomOutWallCreator.IsHasWall(doc, list2))
				{
					foreach (BoundarySegment boundarySegment in list2)
					{
						Curve curve = RevitElementExtension.GetCurve(boundarySegment);
						if (!useArcWall || curve is Line)
						{
							RevitLinkInstance revitLinkInstance = doc.GetElement(boundarySegment.ElementId) as RevitLinkInstance;
							Element element;
							if (revitLinkInstance != null)
							{
								element = revitLinkInstance.GetLinkDocument().GetElement(boundarySegment.LinkElementId);
							}
							else
							{
								element = doc.GetElement(boundarySegment.ElementId);
							}
							if (element is Wall)
							{
								Wall wall = element as Wall;
								Curve curve2 = (wall.Location as LocationCurve).Curve;
								curve2.GetEndPoint(0);
								curve2.GetEndPoint(1);
								try
								{
									XYZ xyz = curve2.Evaluate(0.5, true);
									Curve curve3 = curve.Clone();
									curve3.MakeUnbound();
									XYZ xyz2 = curve3.Project(xyz).XYZPoint - xyz;
									xyz2 = new XYZ(xyz2.X, xyz2.Y, 0.0);
									OutWallData item = new OutWallData
									{
										Curve = curve,
										Element = wall,
										Orientation = xyz2
									};
									list.Add(item);
									continue;
								}
								catch
								{
									continue;
								}
							}
							OutWallData item2 = new OutWallData
							{
								Curve = curve,
								Element = null
							};
							list.Add(item2);
						}
					}
				}
			}
			return list;
		}

		private readonly Document Doc;

		private readonly IDualStatusProgressBarProcess DualStatusProgressBarProcess;

		private readonly IList<ViewPlan> ArrayViewPlan;

		public delegate List<OutWallData> DetermineAdjacentElementLengthsAndWallAreasDel(Autodesk.Revit.DB.Document doc, Room room, bool isArc);
	}
}
